import React from "react";
import { Icon } from "antd";
import ReactDOM from "react-dom";
import configureStore from "stores";

import "styles/components/slide-frame.scss";

/**
 * 侧拉组件，该组件内部组件将自带this.props.close(params)方法关闭侧拉栏
 *
 * 2018/11/26 zaranengap
 * 这个组件是在antd官方出抽屉组件之前写的
 * 所以别再吐槽为什么不用antd官方的组件
 * 虽然不是官方的，但是作者我觉得他既简洁又好用，是个好组件
 * 之后antd出了类似的组件就证明了
 *
 */
class SlideFrame extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      className: "slide-frame animated hide",
      showFlag: false,
    };
  }

  componentDidMount() {
    const { show, className } = this.props;
    show && this.show();
    if (className && className.startsWith("full-width")) {
      window.removeEventListener("resize", this.onResizeWin);
      window.addEventListener("resize", this.onResizeWin);
    }
  }

  /**
   * 根据传入的show值进行判断是否显示
   * @param nextProps
   */
  componentWillReceiveProps(nextProps) {
    const { showFlag } = this.state;
    if (nextProps.show !== showFlag) {
      if (nextProps.show) {
        this.show();
      } else {
        this.close();
      }
    }
  }

  onResizeWin = () => {
    console.log("onResizeWin2");
    const dom = document.querySelector(".slide-frame.animated");
    if (dom) {
      const width = configureStore.store.getState().main.menuWidth;
      dom.style.transition = "all 0.3s ease";
      dom.style.width = `calc(100vw - ${width}px)`;
      dom.className = dom.className.replace(
        /full-width-([\d]+)/,
        `full-width-${width}`
      );
    }
  };

  /**
   * 组装方法
   * @param content 内部组件
   * @return {*} 给组件添加this.props.close(params)方法,params为返回到最外层的值
   *             同时添加外部传入的props为内部组件可用
   */
  wrapClose = (content) => {
    const { params } = this.props;
    const newProps = {
      close: this.close,
      params,
      wrappedComponentRef: (form) => (this.form = form),
    };
    return React.createElement(content, { ...params, ...newProps });
  };

  show = () => {
    const className = `slide-frame animated${
      window.ISIE9 ? "" : " slideInRight"
    }`;
    this.setState({
      className,
      showFlag: true,
    });
  };

  /**
   * 直接关闭，没有动画
   * @param params
   */
  closeDirect = (params) => {
    const { afterClose } = this.props;
    this.setState(
      {
        showFlag: false,
        className: "slide-frame animated hide",
      },
      () => {
        afterClose(params);
      }
    );
  };

  /**
   * 关闭方法，如果内部有params参数，则传出至afterClose方法
   * @param params
   */
  close = (params) => {
    //IE9不支持动画，取消掉500的动画延迟
    if (window.ISIE9) {
      this.closeDirect(params);
    } else {
      this.setState({
        className: "slide-frame animated slideOutRight",
      });
      setTimeout(() => {
        this.closeDirect(params);
      }, 501);
    }
  };

  render() {
    const { showFlag, className } = this.state;
    const {
      cusClass,
      width,
      height,
      top,
      title,
      hasMask,
      onClose,
      hasFooter,
      hasPadding,
      content,
      isShowCloseBtn,
    } = this.props;
    return (
      <div>
        <div
          className={hasMask && showFlag ? "slide-mask" : "hide"}
          onClick={onClose}
        />
        <div
          className={`${className} ${cusClass}`}
          style={{ width, height, top }}
        >
          <div className="slide-title">
            {title}
            {isShowCloseBtn && (
              <Icon type="close" className="close-icon" onClick={onClose} />
            )}
          </div>
          <div
            className={`slide-content ${!hasFooter && "no-footer"}  ${
              !hasPadding && "no-padding"
            }`}
          >
            {this.wrapClose(content)}
          </div>
        </div>
      </div>
    );
  }
}

SlideFrame.propTypes = {
  isShowCloseBtn: React.PropTypes.bool, //是否显示右上角关闭按钮,
  cusClass: React.PropTypes.any, //css class
  width: React.PropTypes.any, //宽度
  height: React.PropTypes.any, //高度
  top: React.PropTypes.any, //顶部
  title: React.PropTypes.any, //标题
  show: React.PropTypes.bool, //是否显示
  hasMask: React.PropTypes.bool, //是否有遮罩层
  onClose: React.PropTypes.func, //点击遮罩层或右上方x时触发的事件
  content: React.PropTypes.oneOfType([
    React.PropTypes.func,
    React.PropTypes.string,
  ]), //内容component，包裹后的元素添加this.props.close方法进行侧滑关闭
  afterClose: React.PropTypes.func, //关闭后触发的事件，用于更新外层的show值
  params: React.PropTypes.object, //外部传入内部组件props
  hasFooter: React.PropTypes.bool, //是否有底端操作区
  hasPadding: React.PropTypes.bool, //是否有内边框
};

SlideFrame.defaultProps = {
  isShowCloseBtn: true,
  cusClass: "",
  width: "50%",
  height: "100%",
  top: 0,
  onClose: () => {},
  hasMask: true,
  afterClose: () => {},
  params: {},
  hasFooter: true,
  hasPadding: true,
};

SlideFrame.destroyFns = [];

SlideFrame.open = function (config = {}, env) {
  const afterClose = config.afterClose || (() => {});
  let contentRef = null;
  const defaultConfig = {
    width: "800px",
    show: true,
    onClose: close,
    onRef: (ref) => !contentRef && (contentRef = ref),
    onWrappedComponentRef: (ref) => !contentRef && (contentRef = ref),
  };
  let targetConfig = {
    ...defaultConfig,
    ...config,
    afterClose: (args) => {
      const { content } = config;
      const afterCloseParams =
        content && content.afterCloseParams
          ? content.afterCloseParams(contentRef)
          : undefined;
      afterClose(afterCloseParams || args);
      destroy();
    },
  };
  let div = document.createElement("div");
  const container = document.body;
  container.appendChild(div);
  function render(props) {
    if (env) {
      ReactDOM.unstable_renderSubtreeIntoContainer(
        env,
        <SlideFrame {...props} />,
        div
      );
    } else {
      ReactDOM.render(<SlideFrame {...props} />, div);
    }
  }
  function destroy() {
    if (div) {
      ReactDOM.unmountComponentAtNode(div);
      container.removeChild(div);
      div = null;
      for (let i = 0; i < SlideFrame.destroyFns.length; i++) {
        const fn = SlideFrame.destroyFns[i];
        if (fn === close) {
          SlideFrame.destroyFns.splice(i, 1);
          break;
        }
      }
    }
  }
  function close() {
    targetConfig = {
      ...targetConfig,
      show: false,
    };
    render(targetConfig);
    setTimeout(destroy, 502);
  }
  function update(updateConfig) {
    targetConfig = {
      ...targetConfig,
      ...updateConfig,
    };
    render(targetConfig);
  }
  render(targetConfig);
  SlideFrame.destroyFns.push(close);
  return {
    destroy: close,
    update,
  };
};
export default SlideFrame;
